//
//  EAGLView.m
//  MathMastersAsteroids
//
//  Created by Jordon Phillips on 3/1/10.
//  Copyright __MyCompanyName__ 2010. All rights reserved.
//

#import "EAGLView.h"

#import "ES1Renderer.h"

@implementation EAGLView

@synthesize animating, bulletCount, scoreDisplay, score, healthBar, timeBar, equationTime, equationTimeMax, equationDisplay,equation, correct, wrong, player, pause, difficulty, soundToggle, musicToggle;
@dynamic animationFrameInterval;

//Game setup:  Graphical items are displayed in the order they are added to the renderer
- (void)initGame{
	//setup background
	Sprite *background = [[Sprite alloc] init];
	background.xPos = 75;
	background.yPos = 50;
	background.scale = 150;
	background.image = 0;
	[renderer addSprite:background];
	[background release];
	
	//setup player
	player = [[Player alloc] init];
	[player initPlayer];
	[renderer addSprite:player.sprite];
	
	//setup asteroids
	int num;
	if(difficulty==2)
		num = arc4random()%10;
	else
		num = arc4random()%6;
	asteroids[0] = [[Asteroid alloc] init];
	[asteroids[0] initAsteroid:0 :25 :num];
	if(difficulty==2)
		num = arc4random()%10;
	else
		num = arc4random()%6;
	asteroids[1] = [[Asteroid alloc] init];
	[asteroids[1] initAsteroid:0 :50 :num];
	if(difficulty==2)
		num = arc4random()%10;
	else
		num = arc4random()%6;
	asteroids[2] = [[Asteroid alloc] init];
	[asteroids[2] initAsteroid:0 :75 :num];
	
	[renderer addSprite:asteroids[0].sprite];
	[renderer addSprite:asteroids[0].number.sprite];
	[renderer addSprite:asteroids[0].number.explosion];
	[renderer addSprite:asteroids[1].sprite];
	[renderer addSprite:asteroids[1].number.sprite];
	[renderer addSprite:asteroids[1].number.explosion];
	[renderer addSprite:asteroids[2].sprite];
	[renderer addSprite:asteroids[2].number.sprite];
	[renderer addSprite:asteroids[2].number.explosion];
	
	starField = [[Sprite alloc] init];
	starField.xPos = 0;
	starField.yPos = 50;
	starField.scale = 300;
	starField.image = 21; 
	[renderer addSprite:starField];
	
	//setup timers
	bulletCount = 0;
	asteroid1Timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(generateAsteroid1) userInfo:nil repeats:YES];
	asteroid2Timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(generateAsteroid2) userInfo:nil repeats:YES];
	asteroid3Timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(generateAsteroid3) userInfo:nil repeats:YES];
	equationTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(equationCountDown) userInfo:nil repeats:YES];
	difficultyTimer = [NSTimer scheduledTimerWithTimeInterval:20 target:self selector:@selector(adjustDifficulty) userInfo:nil repeats:YES];
	
	//setup gui
	
	//the gui background
	Sprite *guiBack = [[Sprite alloc] init];
	guiBack.xPos = 75;
	guiBack.yPos = 75;
	guiBack.scale = 150;
	guiBack.image = 15; 
	[renderer addSprite:guiBack];
	[guiBack release];
	//healthbar xpos 11= empty xpos 75 = full
	healthBar = [[Sprite alloc] init];
	healthBar.xPos = 75;
	healthBar.yPos = 75;
	healthBar.scale = 150;
	healthBar.image = 16; 
	[renderer addSprite:healthBar];
	//timebar xpos -15=empty xpos 75=full
	timeBar = [[Sprite alloc] init];
	timeBar.xPos = 75;
	timeBar.yPos = 75;
	timeBar.scale = 150;
	timeBar.image = 17; 
	[renderer addSprite:timeBar];
	equationTime=30;
	equationTimeMax=30;
	
	//the gui foreground
	Sprite *gui = [[Sprite alloc] init];
	gui.xPos = 75;
	gui.yPos = 75;
	gui.scale = 150;
	gui.image = 14; 
	[renderer addSprite:gui];
	[gui release];
	
	//gui text
	//score text
	score = 000000;
	UIColor *bgColor = [[UIColor alloc] initWithWhite:1.0f alpha:0.0f];
	scoreDisplay = [[UILabel alloc] initWithFrame:CGRectMake(257.0f, 340, 100, 90)];
	scoreDisplay.text = [NSString stringWithFormat:@"%i",score];
	scoreDisplay.textAlignment = UITextAlignmentLeft;
	[scoreDisplay setNumberOfLines:1];
	scoreDisplay.backgroundColor = bgColor;
	scoreDisplay.textColor = [UIColor whiteColor];
	scoreDisplay.font = [UIFont fontWithName:@"Arial" size:10];
	scoreDisplay.transform = CGAffineTransformMakeRotation( M_PI/2 );
	[self addSubview:scoreDisplay];
	[self bringSubviewToFront:scoreDisplay];
	
	//equation text
	equation = [[Equation alloc] init];
	[equation generateEquation];
	equationDisplay = [[UILabel alloc] initWithFrame:CGRectMake(248.0f, 380, 100, 90)];
	if(equation.operand==0)
		equationDisplay.text = [NSString stringWithFormat:@"%i +       = %i",equation.firstNumber,equation.solution];
	else if(equation.operand==1)
		equationDisplay.text = [NSString stringWithFormat:@"%i -        = %i",equation.firstNumber,equation.solution];
	else if(equation.operand==2)
		equationDisplay.text = [NSString stringWithFormat:@"%i x       = %i",equation.firstNumber,equation.solution];
	equationDisplay.textAlignment = UITextAlignmentLeft;
	[equationDisplay setNumberOfLines:1];
	equationDisplay.backgroundColor = bgColor;
	equationDisplay.textColor = [UIColor whiteColor];
	equationDisplay.font = [UIFont fontWithName:@"Arial" size:18];
	equationDisplay.transform = CGAffineTransformMakeRotation( M_PI/2 );
	[self addSubview:equationDisplay];
	[self bringSubviewToFront:equationDisplay];
	[bgColor release];
	
	//setup the correct message
	correct = [[Sprite alloc] init];
	correct.xPos = 300;
	correct.yPos = 75;
	correct.scale = 150;
	correct.image = 18;
	[renderer addSprite:correct];
	
	//setup the wrong message
	wrong = [[Sprite alloc] init];
	wrong.xPos = 300;
	wrong.yPos = 75;
	wrong.scale = 150;
	wrong.image = 19; 
	[renderer addSprite:wrong];
	
	//setup sound and music
	sound = [SoundController alloc];
	[sound initSoundController];
	[sound setMusic:@"AsteroidsMusic" filetype:@"wav"];
	[sound addSound:@"correct" filetype:@"wav"];
	[sound addSound:@"wrong" filetype:@"wav"];
	
}

//Game loop
- (void)gameLoop{
	starField.xPos+=10;
	if(starField.xPos>=150)
		starField.xPos=0;
	float touchX = touchPoint.y/3.20f;
	float touchY = 100-touchPoint.x/3.20f;
	if(touchX<=14&&touchY<=11){//check if pause button has been touched
		[self stopAnimation];
		pause=TRUE;
	}
	[self collisionDetection];
	[player act:touchPoint:touchActive];
	[asteroids[0] act];
	[asteroids[1] act];
	[asteroids[2] act];
	[self updateGui];
	[self drawBullets];
}

//resets the touch point
- (void) resetTouchPoint{
	touchPoint.y=player.xPos*3.20f;
	touchPoint.x=((-1*player.yPos)+100)*3.20f;
}

//changes the difficulty
- (void) setDifficulty:(int)newDiff{
	difficulty=newDiff;
	equation.difficulty=newDiff;
}

//turns sound on
- (void) soundOn{
	self.soundToggle=TRUE;
	player.soundToggle=TRUE;
	asteroids[0].soundToggle=TRUE;
	asteroids[1].soundToggle=TRUE;
	asteroids[2].soundToggle=TRUE;
}

//turns sound off
- (void) soundOff{
	self.soundToggle=FALSE;
	player.soundToggle=FALSE;
	asteroids[0].soundToggle=FALSE;
	asteroids[1].soundToggle=FALSE;
	asteroids[2].soundToggle=FALSE;
}

//updates the gui
- (void)updateGui{
	scoreDisplay.text = [NSString stringWithFormat:@"%i",score];
	if(equation.operand==0)
		equationDisplay.text = [NSString stringWithFormat:@"%i +       = %i",equation.firstNumber,equation.solution];
	else if(equation.operand==1)
		equationDisplay.text = [NSString stringWithFormat:@"%i -        = %i",equation.firstNumber,equation.solution];
	else if(equation.operand==2)
		equationDisplay.text = [NSString stringWithFormat:@"%i x       = %i",equation.firstNumber,equation.solution];
	
	if(player.health>=100)
		healthBar.xPos=75;//full
	else if(player.health<=0)
		healthBar.xPos=11;//empty
	else
		healthBar.xPos=((64.0f*((float)player.health/100))+11);
	
	if(equationTime>=equationTimeMax){
		timeBar.xPos=75;//full
		
	}else if(equationTime<=0){
		timeBar.xPos=-15;//empty
	}else{
		}
		timeBar.xPos=((90.0f*((float)equationTime/equationTimeMax))-15);
}

//adjusts the difficulty over time
- (void)adjustDifficulty{
	if(asteroids[0].speed<2.0){
	asteroids[0].speed+=0.01;
	asteroids[1].speed+=0.01;
	asteroids[2].speed+=0.01;
	}
	if(equationTimeMax>10)
		equationTimeMax-=0.1;
}

//counts down the equation time
- (void)equationCountDown{
	equationTime--;
	if(equationTime<=0){
		[equation generateEquation];
		equationTime=equationTimeMax;
	}
}

//clears messages from the screen
- (void)clearMessage{
	correct.xPos=300;
	wrong.xPos=300;
}

//draws the bullets to the screen
- (void)drawBullets{
	int bulletNum = [player getBulletListSize];
	if(bulletCount<bulletNum){//if there is a new bullet add it to the renderer
		for(int i =(bulletCount);i<bulletNum;i++){
			[renderer addSprite:[player getBulletAtIndex:i].sprite];
		}
	}
	bulletCount = bulletNum;
}

//checks if any object has collided with any other object
-(void)collisionDetection{
	for(int i=0;i<3;i++){
		if(!asteroids[i].sprite.dead&&!asteroids[i].explode){
			float asteroidX = asteroids[i].xPos;
			float asteroidY = asteroids[i].yPos;
			float asteroidRadius = 10;
			//check asteroid collision with bullet
			int bulletNum = [player getBulletListSize];
			for(int j =0;j<bulletNum;j++){
				if(![player getBulletAtIndex:j].dead){
					float bulletX= [player getBulletAtIndex:j].xPos;
					float bulletY= [player getBulletAtIndex:j].yPos;
					//check x coords
					if(bulletX>(asteroidX-asteroidRadius-3)&&bulletX<(asteroidX+asteroidRadius)){
						//check y coords
						if(bulletY>(asteroidY-asteroidRadius)&&bulletY<(asteroidY+asteroidRadius)){
							//asteroid i has collided with bullet j
							[player getBulletAtIndex:j].destroy;
							asteroids[i].collideWithBullet;
							if(asteroids[i].explode)
								score+=10;
						}
					}
				}
			}
			//check asteroid collision with player
			//check x coords
			if(player.xPos>(asteroidX-asteroidRadius-8)&&player.xPos<(asteroidX+asteroidRadius+8)){
				//check y coords
				if(player.yPos>(asteroidY-asteroidRadius-8)&&player.yPos<(asteroidY+asteroidRadius+8)){
					//asteroid i has collided with the player
					if(!asteroids[i].sprite.dead&&!asteroids[i].explode)
						[player collideWithAsteroid];
					asteroids[i].collideWithPlayer;
				}
			}
		}else{
			//asteroid is number
			float asteroidX = asteroids[i].xPos;
			float asteroidY = asteroids[i].yPos;
			float asteroidRadius = 7;
			if(!asteroids[i].number.sprite.dead){
				
				int bulletNum = [player getBulletListSize];
				for(int j =0;j<bulletNum;j++){
					if(![player getBulletAtIndex:j].dead){
						float bulletX= [player getBulletAtIndex:j].xPos;
						float bulletY= [player getBulletAtIndex:j].yPos;
						//check x coords
						if(bulletX>(asteroidX-asteroidRadius-3)&&bulletX<(asteroidX+asteroidRadius)){
							//check y coords
							if(bulletY>(asteroidY-asteroidRadius)&&bulletY<(asteroidY+asteroidRadius)){
								//number i has collided with bullet j
								[player getBulletAtIndex:j].destroy;
								asteroids[i].collideWithBullet;
							}
						}
					}
				}	
				
				
				if(player.xPos>(asteroidX-asteroidRadius-8)&&player.xPos<(asteroidX+asteroidRadius+8)){
					//check y coords
					if(player.yPos>(asteroidY-asteroidRadius-8)&&player.yPos<(asteroidY+asteroidRadius+8)){
						//number i has collided with the player
						[player collideWithNumber];
						asteroids[i].collideWithPlayer;
						if([equation checkAnswer:asteroids[i].number.value]){
							score=score+100;
							if(wrong.xPos<300)
								wrong.xPos=300;
							correct.xPos=75;
							if(soundToggle)
								[sound playSound:0];
							messageTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(clearMessage) userInfo:nil repeats:NO];
							[equation generateEquation];
						}else{
							equationTime-=5;
							player.health-=5;
							if(correct.xPos<300)
								correct.xPos=300;
							wrong.xPos=75;
							if(soundToggle)
								[sound playSound:1];
							messageTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(clearMessage) userInfo:nil repeats:NO];
							}
						}
				}
			}
		}
	}
}

//generates asteroid one if it needs to be generated
- (void) generateAsteroid1{
	if((asteroids[0].number.sprite.dead||asteroids[0].xPos>490)&&(!asteroids[0].number.explode)){
		NSLog(@"generate asteroid 1");
		int num;
		if(difficulty==2)
			num = arc4random()%10;
		else
			num = arc4random()%6;
		if((equationTime/equationTimeMax)<=0.5)//if time is getting low increase the chance to be the needed number
			if((arc4random()%3)==0)
				num = equation.secondNumber;
		[asteroids[0] reset:0 :25 :num];
		[renderer addSprite:asteroids[0].sprite];
		[renderer addSprite:asteroids[0].number.sprite];
		[renderer addSprite:asteroids[0].number.explosion];
	}
}
//generates asteroid two if it needs to be generated
- (void) generateAsteroid2{
	if((asteroids[1].number.sprite.dead||asteroids[1].xPos>490)&&(!asteroids[1].number.explode)){
		NSLog(@"generate asteroid 2");
		int num;
		if(difficulty==2)
			num = arc4random()%10;
		else
			num = arc4random()%6;
		if((equationTime/equationTimeMax)<=0.5)//if time is getting low increase the chance to be the needed number
			if((arc4random()%3)==0)
				num = equation.secondNumber;
		[asteroids[1] reset:0 :50 :num];
		[renderer addSprite:asteroids[1].sprite];
		[renderer addSprite:asteroids[1].number.sprite];
		[renderer addSprite:asteroids[1].number.explosion];
	}
	
}
//generates asteroid three if it needs to be generated
- (void) generateAsteroid3{
	if((asteroids[2].number.sprite.dead||asteroids[2].xPos>490)&&(!asteroids[2].number.explode)){
		NSLog(@"generate asteroid 3");
		int num;
		if(difficulty==2)
			num = arc4random()%10;
		else
			num = arc4random()%6;
		if((equationTime/equationTimeMax)<=0.5)//if time is getting low increase the chance to be the needed number
			if((arc4random()%3)==0)
				num = equation.secondNumber;
		[asteroids[2] reset:0 :75 :num];
		[renderer addSprite:asteroids[2].sprite];
		[renderer addSprite:asteroids[2].number.sprite];
		[renderer addSprite:asteroids[2].number.explosion];
	}
	
}


//engine setup
// You must implement this method
+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

//The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
- (id)initWithFrame:(CGRect)frame
{    
    if ((self = [super initWithFrame:frame])) {
        // Get the layer
        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
        
        eaglLayer.opaque = TRUE;
        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                        [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
		
			renderer = [[ES1Renderer alloc] init];
			
			if (!renderer)
			{
				[self release];
				return nil;
			}

        
		animating = FALSE;
		displayLinkSupported = FALSE;
		animationFrameInterval = 1;
		displayLink = nil;
		animationTimer = nil;
		
		// A system version of 3.1 or greater is required to use CADisplayLink. The NSTimer
		// class is used as fallback when it isn't available.
		NSString *reqSysVer = @"3.1";
		NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
		if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
			displayLinkSupported = TRUE;
		[self initGame];
		
    }
	
    return self;
}
//draws the view, this is called every frame
- (void) drawView:(id)sender
{
	[self gameLoop];
    [renderer render];
}

- (void) layoutSubviews
{
	[renderer resizeFromLayer:(CAEAGLLayer*)self.layer];
    [self drawView:nil];
}

- (NSInteger) animationFrameInterval
{
	return animationFrameInterval;
}

- (void) setAnimationFrameInterval:(NSInteger)frameInterval
{
	// Frame interval defines how many display frames must pass between each time the
	// display link fires. The display link will only fire 30 times a second when the
	// frame internal is two on a display that refreshes 60 times a second. The default
	// frame interval setting of one will fire 60 times a second when the display refreshes
	// at 60 times a second. A frame interval setting of less than one results in undefined
	// behavior.
	if (frameInterval >= 1)
	{
		animationFrameInterval = frameInterval;
		
		if (animating)
		{
			[self stopAnimation];
			[self startAnimation];
		}
	}
}
//starts the animaton
- (void) startAnimation
{
	if (!animating)
	{
		if (displayLinkSupported)
		{
			// CADisplayLink is API new to iPhone SDK 3.1. Compiling against earlier versions will result in a warning, but can be dismissed
			// if the system version runtime check for CADisplayLink exists in -initWithCoder:. The runtime check ensures this code will
			// not be called in system versions earlier than 3.1.

			displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(drawView:)];
			[displayLink setFrameInterval:animationFrameInterval];
			[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
		}
		else
			animationTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)((1.0 / 60.0) * animationFrameInterval) target:self selector:@selector(drawView:) userInfo:nil repeats:TRUE];
		if(musicToggle){
			[sound playMusic];
		}
		animating = TRUE;
	}
}
//stops the animation
- (void)stopAnimation
{
	if (animating)
	{
		if (displayLinkSupported)
		{
			[displayLink invalidate];
			displayLink = nil;
		}
		else
		{
			[animationTimer invalidate];
			animationTimer = nil;
		}
		[sound pauseMusic];
		animating = FALSE;
	}
}

//screen has been touched
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	UITouch *touch = [touches anyObject];
	touchPoint = [touch locationInView:self];
	touchActive = TRUE;
}
//the touch has moved
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
	UITouch *touch = [touches anyObject];
	touchPoint = [touch locationInView:self];
	touchActive = TRUE;
}
//touches have ended
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	touchActive = FALSE;
}

- (void) dealloc
{
	[animationTimer release];
    [renderer release];
	[player release];
	[asteroids[0] release];
	[asteroids[1] release];
	[asteroids[2] release];
	[scoreDisplay release];
	[healthBar release];
	[timeBar release];
	[equation release];
	[equationDisplay release];
	[difficultyTimer release];
	[correct release];
	[wrong release];
	[starField release];
	[sound release];
    [super dealloc];
}


@end
